<template>
  <el-upload class="upload-demo" action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList"
    :auto-upload="false" :on-change="handleChange" :on-remove="handleRemove" multiple :show-file-list="false"
    ref="uploadRef">
    <el-button size="small" type="primary">选择文件</el-button>
    <div slot="tip" class="el-upload__tip">只能上传jpg/png文件，且不超过500kb</div>
  </el-upload>

  <el-button type="success" size="small" :disabled="!fileList.length || uploading" @click="submitUpload"
    style="margin-top: 10px">
    {{ uploading ? '上传中...' : '开始上传' }}
  </el-button>

  <el-table v-if="fileList.length" :data="fileList" style="width: 100%; margin-top: 20px" border>
    <el-table-column prop="name" label="文件名称" min-width="200" />
    <el-table-column label="文件大小" width="120">
      <template #default="{ row }">
        {{ formatSize(row.size) }}
      </template>
    </el-table-column>
    <el-table-column label="上传状态" width="120">
      <template #default="{ row }">
        <el-tag v-if="row.status === 'success'" type="success" size="small">成功</el-tag>
        <el-tag v-else-if="row.status === 'uploading'" type="info" size="small">上传中</el-tag>
        <el-tag v-else-if="row.status === 'fail'" type="danger" size="small">失败</el-tag>
        <el-tag v-else size="small">等待上传</el-tag>
      </template>
    </el-table-column>
    <el-table-column label="操作" width="100" align="center">
      <template #default="{ row }">
        <el-button type="text" size="small" @click="removeFile(row)" :disabled="uploading">移除</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup>
import { ref } from 'vue'

const fileList = ref([])
const uploading = ref(false)
const uploadRef = ref(null)

// 格式化文件大小
function formatSize(size) {
  if (size === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(size) / Math.log(k))
  return (size / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i]
}

// 选择文件时触发，更新 fileList，状态初始为 waiting
function handleChange(file, newFileList) {
  fileList.value = newFileList.map(f => ({
    uid: f.uid,
    name: f.name,
    size: f.size,
    status: 'waiting',
    raw: f.raw,
  }))
}

// 移除文件
function handleRemove(file, newFileList) {
  fileList.value = newFileList.map(f => ({
    uid: f.uid,
    name: f.name,
    size: f.size,
    status: 'waiting',
    raw: f.raw,
  }))
}

// 点击“开始上传”按钮，逐个上传文件
async function submitUpload() {
  if (!fileList.value.length) return
  uploading.value = true

  for (const file of fileList.value) {
    // 跳过已成功上传的文件
    if (file.status === 'success') continue

    // 更新状态为 uploading
    updateFileStatus(file.uid, 'uploading')

    try {
      // 调用 el-upload 组件的 submit 方法上传单个文件
      await uploadFile(file)
      updateFileStatus(file.uid, 'success')
    } catch (error) {
      updateFileStatus(file.uid, 'fail')
    }
  }

  uploading.value = false
}

// 通过 el-upload 的 submit 方法上传单个文件，封装成 Promise
function uploadFile(file) {
  return new Promise((resolve, reject) => {
    // 通过 uploadRef 调用 el-upload 的 submit 方法上传指定文件
    uploadRef.value.submit(file.raw)

    // 监听上传成功和失败事件
    const onSuccess = (response, f) => {
      if (f.uid === file.uid) {
        cleanup()
        resolve(response)
      }
    }
    const onError = (err, f) => {
      if (f.uid === file.uid) {
        cleanup()
        reject(err)
      }
    }

    // 绑定事件
    uploadRef.value.$.emit('success', onSuccess)
    uploadRef.value.$.emit('error', onError)

    // 清理事件监听，防止内存泄漏
    function cleanup() {
      uploadRef.value.$.off('success', onSuccess)
      uploadRef.value.$.off('error', onError)
    }
  })
}

// 更新文件状态
function updateFileStatus(uid, status) {
  const index = fileList.value.findIndex(f => f.uid === uid)
  if (index !== -1) {
    fileList.value[index].status = status
  }
}

// 点击“移除”按钮
function removeFile(row) {
  if (uploading.value) return
  fileList.value = fileList.value.filter(f => f.uid !== row.uid)
}
</script>

<style scoped>
.upload-demo {
  width: 400px;
}
</style>
